package com.syblood.app.camera.watermark.codec;

import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.os.Build;
import android.text.TextUtils;
import android.view.Surface;

import com.syblood.app.camera.callback.IMediaEncoderCallback;
import com.syblood.app.constants.Constants;
import com.syblood.app.utils.AppUtil;
import com.syblood.app.utils.FileUtil;
import com.syblood.app.utils.LogUtil;
import com.syblood.app.camera.watermark.utils.GlesUtil;
import com.syblood.app.utils.MediaScanner;


import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * @CreateTime : 2022/12/3 19:22
 * @Author : JiChangkong
 * @Description :音视频编码管理类
 */
public class MediaEncodeManager {
    //录音
    private final AudioCapture audioCapture;
    private String videoFilePath;
    //时间戳
    private long presentationTimeUs;
    //整合音视频工具
    private MediaMuxer mediaMuxer;
    //音频编码
    private MediaCodec audioCodec;
    private MediaCodec.BufferInfo audioBuffer;
    private AudioCodecThread audioThread;
    //标记MediaCodec -- audioCodec 对象是否退出释放
    public static boolean isAudioStop;
    //标记track下标
    public static int audioTrackIndex;
    public static int videoTrackIndex;
    //标记MediaMuxer是否开启
    public static boolean encodeStart;
    //AudioCapture.class类中采集音频采用的位宽：AudioFormat.ENCODING_PCM_16BIT ，此处应传入16bit，
    // 用作计算pcm一帧的时间戳
    private final static int AUDIO_FORMAT = 16;
    private final static int SAMPLE_RATE = 44100;
    private final static int CHANNEL_COUNT = 2;//单声道 channelCount=1 , 双声道  channelCount=2
    //视频编码
    private VideoEncoder videoCodec;

    private IMediaEncoderCallback mediaEncoderCallback = new IMediaEncoderCallback() {
        @Override
        public void onStart() {
            AppUtil.runOnBgThread(new Runnable() {
                @Override
                public void run() {
                    setPcmRecordListener();
                }
            });
        }

        @Override
        public void setPresentationTimeUs(int timeUs) {

        }

        @Override
        public void onStop() {

        }
    };

    public MediaEncodeManager() {
        audioCapture = new AudioCapture();
    }

    public void init(int width, int height) {
        videoFilePath = FileUtil.getVideoFilePath();
        try {
            mediaMuxer = new MediaMuxer(videoFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
            videoCodec = new VideoEncoder(width, height, mediaMuxer,mediaEncoderCallback);

            audioCodec = MediaCodec.createEncoderByType("audio/mp4a-latm");
            MediaFormat audioFormat = MediaFormat.createAudioFormat(
                    "audio/mp4a-latm",
                    SAMPLE_RATE,
                    CHANNEL_COUNT);//单声道 channelCount=1 , 双声道  channelCount=2
            int BIT_RATE = 96000;
            audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
            audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,
                    MediaCodecInfo.CodecProfileLevel.AACObjectLC);
            int MAX_INOUT_SIZE = 8192;
            audioFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, MAX_INOUT_SIZE);
            audioCodec.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            audioBuffer = new MediaCodec.BufferInfo();

            audioThread = new AudioCodecThread(audioCodec, audioBuffer, mediaMuxer,mediaEncoderCallback);
        } catch (IOException e) {
            LogUtil.e("initMediaMuxer: 文件打开失败,path=" + videoFilePath);
        }
    }

    //录音线程数据回调
    private void setPcmRecordListener() {
        if (audioCapture.getCaptureListener() == null)
            audioCapture.setCaptureListener((audioSource, audioReadSize) -> {
                if (isAudioStop) {
                    return;
                }
                setPcmSource(audioSource, audioReadSize);
                //计算分贝的一种方式
                AppUtil.postInUiThread(() -> {
                    double dBValue = GlesUtil.calcDecibelValue(audioSource, audioReadSize);
                    LogUtil.d("calcDecibelLevel: 分贝值 = " + dBValue);
                }, 200);
            });
    }

    public void setPcmSource(byte[] pcmBuffer, int buffSize) {
        if (audioCodec == null) {
            return;
        }
        try {

            int buffIndex = audioCodec.dequeueInputBuffer(0);
            if (buffIndex < 0) {
                return;
            }
            ByteBuffer byteBuffer;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                byteBuffer = audioCodec.getInputBuffer(buffIndex);
            } else {
                byteBuffer = audioCodec.getInputBuffers()[buffIndex];
            }
            if (byteBuffer == null) {
                return;
            }
            byteBuffer.clear();
            byteBuffer.put(pcmBuffer);
            //presentationTimeUs = 1000000L * (buffSize / 2) / sampleRate
            //一帧音频帧大小 int size = 采样率 x 位宽 x 采样时间 x 通道数
            // 1s时间戳计算公式  presentationTimeUs = 1000000L * (totalBytes / sampleRate/ audioFormat / channelCount / 8 )
            //totalBytes : 传入编码器的总大小
            //1000 000L : 单位为 微秒，换算后 = 1s,
            //除以8     : pcm原始单位是bit, 1 byte = 8 bit, 1 short = 16 bit, 用 Byte[]、Short[] 承载则需要进行换算
            presentationTimeUs += (long) (1.0 * buffSize / (SAMPLE_RATE * CHANNEL_COUNT * (AUDIO_FORMAT / 8)) * 1000000.0);
            LogUtil.d("pcm一帧时间戳 = " + presentationTimeUs / 1000000.0f);
            audioCodec.queueInputBuffer(buffIndex, 0, buffSize, presentationTimeUs, 0);
        } catch (java.lang.IllegalStateException e) {
            //audioCodec 线程对象已释放MediaCodec对象
            LogUtil.d("setPcmSource: " + "MediaCodec对象已释放");
        }
    }

    public Surface getInputSurface() {
        return videoCodec.getInputSurface();
    }

    public void stopEncoder() {
        videoCodec.drainEncoder(true);
        audioThread.stopAudioCodec();
        audioThread = null;
        audioCapture.stop();
        isAudioStop = true;
    }

    public void startAudio() {
        isAudioStop = false;
        audioThread.start();
        audioCapture.start();
    }

    public void drainEncoder() {
        videoCodec.drainEncoder(false);
    }

    public void release() {
        MediaEncodeManager.encodeStart = false;
        videoCodec.release();
        videoCodec = null;
        MediaScanner.getInstance().scanFile(videoFilePath, Constants.MEDIA_TYPE_VIDEO);
        mediaEncoderCallback.onStop();
        videoFilePath = null;
        if (mediaMuxer != null) {
            mediaMuxer.stop();
            mediaMuxer.release();
            mediaMuxer = null;
        }
    }


    public void onDestroy() {
    }
}
